package com.pan.download5.driver;

import com.pan.crawler.Directory;
import com.pan.crawler.Page;
import com.pan.download5.config.ApplicationConfig;
import com.pan.download5.ctrl.*;
import com.pan.download5.factory.DirectoryFactory;
import com.pan.download5.factory.PageFactory;
import com.pan.download5.factory.impl.CommonDirectoryFactory;
import com.pan.download5.factory.impl.CommonPageFactory;
import com.pan.entity.BookDirectory;
import com.pan.entity.Chapter;

import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.concurrent.*;

public class Basic2Driver implements Driver{



    private DirectoryFactory directoryFactory;
    private PageFactory pageFactory;

//    public Basic2Driver(Class<? extends Page> pageClass,Class<? extends Directory> directoryClass) {
//        this.directoryFactory = new CommonDirectoryFactory(directoryClass);
//        this.pageFactory = new CommonPageFactory(pageClass);
//    }

    public Basic2Driver(DirectoryFactory directoryFactory, PageFactory pageFactory){
        this.directoryFactory = directoryFactory;
        this.pageFactory = pageFactory;
    }

    private BookDirectory getBookDirectory(DirectoryFactory directoryFactory, String url){
        Directory directory = directoryFactory.createDirectory();
        int taskErrorCount = ApplicationConfig.INSTANCE.getTaskErrorCount();
        BookDirectory bookDirectory ;
        for (int i=0;;i++) {
            try {
                bookDirectory = directory.get(url);
                break;
            } catch (Exception e) {
                String errorMessage = "章节信息爬取失败 "+(i+1)+"次";
                System.out.println(errorMessage);
                System.out.println(e);
                if (i == taskErrorCount-1) {
                    throw new RuntimeException(errorMessage, e);
                }
            }
        }
        return bookDirectory;
    }

    @Override
    public void run(String url, int threadCount) {


        //多线程执行，优化效率
        //爬取目录信息
        FutureTask<BookDirectory> bookDirectoryFuture = new FutureTask<>(()->this.getBookDirectory(directoryFactory, url));
        //爬取页面的初始化
        FutureTask<Page[]> pageFuture = new FutureTask<>(()->{
            Page[] pageArr = new Page[threadCount];
            for (int i = 0; i < threadCount; i++) pageArr[i] = pageFactory.createPage();
            return pageArr;
        });
        new Thread(bookDirectoryFuture).start();
        new Thread(pageFuture).start();

        BookDirectory bookDirectory;
        Page[] pageArr;
        try {
            bookDirectory = bookDirectoryFuture.get();
            pageArr = pageFuture.get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }


        List<Chapter> chapterList = bookDirectory.getChapterList();
        String bookName = bookDirectory.getBookName();
        System.out.println("开始爬取："+bookName);
        TaskSyncPublish taskPublish = new ArrayTaskPublish(chapterList);
        ChapterSyncWriter chapterSyncWriter = new ChapterSyncWriterImpl2(bookName);
        CountDownLatch countDownLatch = new CountDownLatch(threadCount);
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(threadCount, threadCount,
                //这三个参数在这里是无关紧要的,因为线程数量是固定的任务数量是固定的。
                114514, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10));
        for (int i = 0; i < threadCount; i++) {
            TaskHandle taskHandle = new TaskHandleImpl2(pageArr[i], taskPublish, chapterSyncWriter,countDownLatch);
            poolExecutor.execute(taskHandle);
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        chapterSyncWriter.close();
        poolExecutor.shutdown();
        System.out.println("爬取完成："+bookName+"!");
    }
}
